package com.cat.orm.core.db.repository;

import com.cat.orm.core.base.BasePo;
import com.cat.orm.core.base.IBasePo;
import com.cat.orm.core.db.repository.dao.IBaseDao;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.*;

/**
 * @author Jeremy Feng
 * @date 2024/8/27 20:38
 */
public abstract class AbstractDataRepository<D extends IBaseDao<BasePo>> implements IRepository {

    /**
     * name, 类名 value: dao 存储dao
     */
    protected Map<String, D> commonDaoMap;

    public AbstractDataRepository(Collection<Class<BasePo>> basePos, JdbcTemplate jdbcTemplate) {
        this.commonDaoMap = new HashMap<>();
        for (Class<BasePo> basePo : basePos) {
            D dao = this.createDao(basePo, jdbcTemplate);
            commonDaoMap.put(basePo.getSimpleName().toLowerCase(), dao);// 注意,通过spring注入进来的Map, key默认全部小写
        }
    }

    /**
     * 创建一个Dao
     * @return dao对象
     */
    public abstract D createDao(Class<BasePo> basePo, JdbcTemplate jdbcTemplate);

    @SuppressWarnings("unchecked")
    public <T extends IBasePo> IBaseDao<T> getCommonDao(String name) {
        if (name == null || name.equals("")) {
            throw new NullPointerException("name is can not be null:" + name);
        }
        return (IBaseDao<T>) commonDaoMap.get(name);
    }

    public <T extends IBasePo> IBaseDao<T> getCommonDao(Class<T> clazz) {
        if (clazz == null) {
            throw new NullPointerException("clazz is can not be null:" + clazz);
        }
        String name = clazz.getSimpleName().toLowerCase();
        return getCommonDao(name);
    }

    public <T extends IBasePo> IBaseDao<T> getCommonDao(T clazz) {
        if (clazz == null) {
            throw new NullPointerException("clazz is can not be null:" + clazz);
        }
        return getCommonDao(clazz.poName().toLowerCase());
    }

    /**
     * 查询信息
     * @date 2020年6月30日
     * @param clazz 类
     * @return 查询结果集合
     */
    public <T extends IBasePo> List<T> selectAll(Class<T> clazz) {
        IBaseDao<T> dao = getCommonDao(clazz);
        if (dao == null) {
            throw new NullPointerException("Can not find dao by the clazz:" + clazz);
        }
        return (List<T>) dao.selectAll();
    }

    /**
     * 查询信息
     *
     * @date 2020年6月30日
     * @param clazz
     * @return
     */
    public <T extends IBasePo> T selectByPrimaryKey(Class<T> clazz, Object value) {
        IBaseDao<T> dao = getCommonDao(clazz);
        if (dao == null) {
            throw new NullPointerException("Can not find dao by the clazz:" + clazz);
        }
        return dao.selectByKey(value);
    }

    /**
     * 查询玩家信息, 通过默认索引,这种方式直接获取缓存的sql进行查询
     *
     * @date 2020年6月30日
     * @param clazz
     * @return
     */
    public <T extends IBasePo> List<T> selectByIndex(Class<T> clazz, Object[] objs) {
        IBaseDao<T> dao = getCommonDao(clazz);
        if (dao == null) {
            throw new NullPointerException("Can not find dao by the clazz:" + clazz);
        }
        return (List<T>) dao.selectByIndex(objs);
    }

    /**
     * 查询玩家信息, 通过默认索引,这种方式直接获取缓存的sql进行查询
     *
     * @date 2020年6月30日
     * @param clazz
     * @return
     */
    public <T extends IBasePo> T selectOneByIndex(Class<T> clazz, Object[] objs) {
        List<T> ret = this.selectByIndex(clazz, objs);
        if (ret == null || ret.size() <= 0) {
            return null;
        }
        return ret.get(0);
    }

    /**
     * 查询玩家信息, 通过制定字段,这种方式只能通过sql组装进行查询
     *
     * @date 2020年6月30日
     * @param clazz
     * @return
     */
    public <T extends IBasePo> List<T> selectByIndex(Class<T> clazz, String[] props, Object[] objs) {
        IBaseDao<T> dao = getCommonDao(clazz);
        if (dao == null) {
            throw new NullPointerException("Can not find dao by the props:" + props);
        }
        return (List<T>) dao.selectByIndex(props, objs);
    }

    /**
     * 添加玩家信息
     *
     * @date 2020年6月30日
     * @param po
     */
    public <T extends IBasePo> int insert(T po) {
        IBaseDao<T> dao = getCommonDao(po);
        if (dao == null) {
            throw new NullPointerException("Can not find dao by the Pojo:" + po);
        }
        return dao.insert(po);
    }

    /**
     * 批量添加
     *
     * @date 2020年6月30日
     * @param basePos
     */
    public <T extends IBasePo> void insertBatch(Collection<T> basePos) {
        Map<String, List<T>> map = splitData(basePos);
        IBaseDao<T> dao = null;
        for (String name : map.keySet()) {
            dao = getCommonDao(name);
            dao.insertBatch(map.get(name));
        }
        map = null;
    }

    /**
     * 添加玩家信息
     *
     * @date 2020年6月30日
     * @param po
     */
    public <T extends IBasePo> int replace(T po) {
        IBaseDao<T> dao = getCommonDao(po);
        if (dao == null) {
            throw new NullPointerException("Can not find dao by the Pojo:" + po);
        }
        return dao.replace(po);
    }

    /**
     * 添加玩家信息
     *
     * @date 2020年6月30日
     * @param po
     */
    public <T extends IBasePo> int update(T po) {
        IBaseDao<T> dao = getCommonDao(po);
        if (dao == null) {
            throw new NullPointerException("Can not find dao by the Pojo:" + po);
        }
        return dao.update(po);
    }

    /**
     * 批量修改玩家信息
     *
     * @date 2020年6月30日
     * @param pos 代保存对象
     */
    public <T extends IBasePo> int updateBatch(Collection<T> pos) {
        Map<String, List<T>> map = splitData(pos);
        IBaseDao<T> dao = null;
        for (String name : map.keySet()) {
            dao = getCommonDao(name);
            dao.updateBatch(map.get(name));
        }
        return 0;
    }

    /**
     * 添加玩家信息
     *
     * @date 2020年6月30日
     * @param po
     */
    public <T extends IBasePo> int delete(T po) {
        IBaseDao<T> dao = getCommonDao(po);
        if (dao == null) {
            throw new NullPointerException("Can not find dao by the Pojo:" + po);
        }
        return dao.delete(po);
    }

    /**
     * 删除所有
     *
     * @date 2020年6月30日
     * @param clazz 删除指定类所有数据
     */
    public <T extends IBasePo> void deleteAll(Class<T> clazz) {
        IBaseDao<T> dao = getCommonDao(clazz);
        if (dao == null) {
            throw new NullPointerException("Can not find dao by the clazz:" + clazz);
        }
        dao.deleteAll();
    }

    /**
     * 批量删除
     *
     * @date 2020年6月30日
     * @param basePos
     */
    public <T extends IBasePo> void deleteBatch(List<T> basePos) {
        Map<String, List<T>> map = splitData(basePos);
        IBaseDao<T> dao = null;
        for (String name : map.keySet()) {
            dao = getCommonDao(name);
            dao.deleteBatch(map.get(name));
        }
        map = null;
    }

    /**
     * 通过指定sql查询. 虽说指定了sql语句,但需要通过clazz获取处理dao
     * @date 2020年6月30日
     * @param clazz 待保存类, 数据库查询语句
     */
    public <T extends IBasePo> List<T> selectBySql(Class<T> clazz, String sql) {
        IBaseDao<T> dao = getCommonDao(clazz);
        if (dao == null) {
            throw new NullPointerException("Can not find dao by the clazz:" + clazz);
        }
        return (List<T>) dao.selectBySql(sql);
    }

    /**
     * 数据分类
     *
     * @date 2020年8月5日
     * @param basePos
     * @return
     */
    protected <T extends IBasePo> Map<String, List<T>> splitData(Collection<T> basePos) {
        // 数据分类
        Map<String, List<T>> map = new HashMap<String, List<T>>();
        for (T po : basePos) {
            String name = po.poName().toLowerCase();
            List<T> list = map.get(name);
            if (list == null) {
                list = new ArrayList<T>();
                map.put(name, list);
            }
            list.add(po);
        }
        return map;
    }

    @Override
    public <T extends IBasePo> void execute(Class<T> clazz, String sql) {
        IBaseDao<T> dao = getCommonDao(clazz);
        if (dao == null) {
            throw new NullPointerException("Can not find dao by the clazz:" + clazz);
        }
        dao.execute(sql);
    }

}
